/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bakenote.ui;

import bakenote.components.TabButtonDataRenderer;
import bakenote.core.*;
import bakenote.data.RecipeSQLiteDB;
import bakenote.data.RecipeGroupList;
import bakenote.data.RecipeList;
import bakenote.xml.ExportXMLTask;
import bakenote.xml.ImportXMLTask;
import org.apache.pivot.beans.BXML;
import org.apache.pivot.beans.BXMLSerializer;
import org.apache.pivot.beans.Bindable;
import org.apache.pivot.collections.*;
import org.apache.pivot.collections.List;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.util.Filter;
import org.apache.pivot.util.Resources;
import org.apache.pivot.util.concurrent.TaskExecutionException;
import org.apache.pivot.wtk.*;
import org.apache.pivot.wtk.Button;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.Dialog;
import org.apache.pivot.wtk.Menu;
import org.apache.pivot.wtk.Window;
import org.apache.pivot.wtk.content.TreeBranch;
import org.apache.pivot.wtk.content.TreeNode;
import org.apache.pivot.wtk.content.TreeViewNodeEditor;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author lello
 */
public class BakeNoteWindow extends Window implements Bindable {

    // Variables declared in the BXML file
    @BXML
    private TabPane recipeTabPane = null;
    @BXML
    private RecipeTablePane recipeTablePane = null;
    @BXML
    private TreeView groupTreeView = null;
    @BXML
    private Dialog aboutDialog = null;
    @BXML
    private Menu.Item addRecipeMenuItem = null;
    @BXML
    private Menu.Item deleteRecipeMenuItem = null;
    @BXML
    private Menu.Item editRecipeMenuItem = null;
    @BXML
    private Menu.Item importMenuItem = null;
    @BXML
    private Menu.Item exportMenuItem = null;
    @BXML
    private Menu.Item databaseMenuItem = null;
    @BXML
    private Menu.Item aboutMenuItem = null;

    private Dialog newGroupDialog = null;
    // The textInput to enter the new recipe group Name
    private TextInput groupTextInput;
    private RecipeEditorPane recipeEditorPane = null;
    // Local variables
    private BakeNoteWindow window = null;
    private RecipeTab recipeTab = null;
    // cache the recipeTab for later use (--> see editRecipe)
    private RecipeTab previousTab = null;
    // This store the current selected recipe
    private Recipe selectedRecipe = null;
    private RecipeGroup selectedRecipeGroup = null;
    //private int selectedRecipeTabIndex;
    private List<Recipe> selectedRecipeList = new ArrayList<Recipe>();
    private PushButton groupOKButton = null;


    public BakeNoteWindow() {
        //No-op constructor
    }

    ButtonPressListener exportButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {

            if (!isSelectedRecipeListEmpty()) {
                try {
                    final FileBrowserSheet fileBrowser = new FileBrowserSheet();
                    fileBrowser.setMode(FileBrowserSheet.Mode.SAVE_AS);
                    fileBrowser.open(window, new SheetCloseListener() {

                        public void sheetClosed(Sheet sheet) {
                            if (sheet.getResult()) {
                                File selectedFile = fileBrowser.getSelectedFile();
                                ExportXMLTask xmlExport = new ExportXMLTask(selectedFile, selectedRecipeList);
                                try {
                                    xmlExport.execute();
                                } catch (Exception ex) {
                                    Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                        }
                    });
                } catch (Exception ex) {
                    Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    };

    ButtonPressListener importButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {

            try {
                final FileBrowserSheet fileBrowser = new FileBrowserSheet();
                fileBrowser.setMode(FileBrowserSheet.Mode.OPEN);
                fileBrowser.open(window, new SheetCloseListener() {

                    public void sheetClosed(Sheet sheet) {
                        if (sheet.getResult()) {
                            File selectedFile = fileBrowser.getSelectedFile();
                            ImportXMLTask xmlImport = new ImportXMLTask(selectedFile);
                            try {
                                xmlImport.execute();
                                selectedRecipe = xmlImport.getRecipe();
                                recipeTablePane.getRecipeTableView().setSelectedRow(selectedRecipe);
                            } catch (TaskExecutionException ex) {
                                Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    }
                });

            } catch (Exception ex) {
                Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    };

    ButtonPressListener databaseButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {

            try {
                Filter<File> fileFilter = new Filter<File>() {
                    @Override
                    public boolean include(File file) {
                        return !file.isDirectory();
                    }
                };
                final FileBrowserSheet fileBrowser = new FileBrowserSheet();
                fileBrowser.setDisabledFileFilter(fileFilter);
                // SAVE_TO us the only way to allow the selection of a directory...this is a known bug
                fileBrowser.setMode(FileBrowserSheet.Mode.SAVE_TO);
                fileBrowser.open(window, new SheetCloseListener() {
                    public void sheetClosed(Sheet sheet) {
                        if (sheet.getResult()) {
                            File selectedFile = fileBrowser.getSelectedFile();
                            if (selectedFile.isDirectory()) {
                                try {
                                    // TODO: not working..
                                    System.out.println("file "+selectedFile);
                                    RecipeSQLiteDB.openDatabase(selectedFile.getAbsolutePath());
                                } catch (SQLException e) {
                                    Alert.alert(MessageType.ERROR, "Cannot open database.", window);
                                    //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                                }
                            }
                        }
                    }
                });
            } catch (Exception ex) {
                Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    };

    ButtonPressListener addRecipeMenuItemListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {
            // we must set the previousTab to null; since a previous editing might have
            // defined a previousTab.
            previousTab = null;
            if (recipeEditorPane == null) {
                //System.out.println("recipe editor window null...");
                //serializeRecipeEditorPane();
                newRecipeEditorPane();
                recipeEditorPane.disableSaveAsNewButton();
                recipeTabPane.getTabs().add(recipeEditorPane);
            }
        }
    };

    ButtonPressListener editRecipeMenuItemListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {
            int index = -1;
            if (recipeEditorPane == null) {
                if (isRecipeSelected()) {
                    //serializeRecipeEditorPane();
                    newRecipeEditorPane();
                    recipeEditorPane.editRecipe(selectedRecipe);
                    //recipeEditorPane.setName(selectedRecipe.getName());

                    // Check whether we have a tab displaying the selected recipe
                    for (Component co : recipeTabPane.getTabs()) {
                        try {
                            RecipeTab rt = (RecipeTab) co;
                            if (rt.getRecipe().equals(selectedRecipe)) {
                                index = recipeTabPane.getTabs().indexOf(co);
                                previousTab = rt;
                                recipeTabPane.setSelectedIndex(index);
                            }
                        } catch (ClassCastException cce) {
                            // the first tab cannot be cast to RecipeTab it is a simple tablepane
                            //System.out.println("cannot cast");
                        }
                    }

                    if (index > -1) {
                        recipeTabPane.getTabs().remove(index, 1);
                        recipeTabPane.getTabs().insert(recipeEditorPane, index);
                    } else {
                        recipeTabPane.getTabs().add(recipeEditorPane);
                    }

                }
            } else {
                Alert.alert(MessageType.ERROR, "You are already editing a recipe.", window);
            }
        }
    };
    ButtonPressListener deleteButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {
            if (!isSelectedRecipeListEmpty()) {
                String s = "";
                for (Recipe r : selectedRecipeList) {
                    s += r.getName() + " ";
                }
                String title = "Permanently delete recipe(s) \"" + s + "\"?";
                new Alert(MessageType.QUESTION, title, new ArrayAdapter("Delete", "Cancel")).open(window, new DialogCloseListener() {
                    public void dialogClosed(Dialog dialog, boolean modal) {
                        if (((Alert) dialog).getSelectedOption().equals("Delete")) {
                            deleteRecipes();
                        } else {
                            dialog.close();
                        }
                        ;
                    }
                });
            }
        }
    };
    TableViewSelectionListener recipeTableViewSelectionListener = new TableViewSelectionListener() {

        public void selectedRangeAdded(TableView tv, int i, int i1) {
            //System.out.println("selection added");
            updateSelection(tv);
        }

        public void selectedRangeRemoved(TableView tv, int i, int i1) {
            //System.out.println("selection removed");
            updateSelection(tv);
        }

        public void selectedRangesChanged(TableView tv, Sequence<Span> sqnc) {
            //System.out.println("selected ranges changed");
            updateSelection(tv);
        }

        public void selectedRowChanged(TableView tv, Object o) {
            // only in single mode selection
            //System.out.println("selected row changed");
            updateSelection(tv);
        }

        private void updateSelection(TableView tableView) {
            selectedRecipeList.clear();
            Sequence<Span> selectedRanges = tableView.getSelectedRanges();
            for (int i = 0; i < selectedRanges.getLength(); i++) {
                Span selectedRange = selectedRanges.get(i);
                for (int j = selectedRange.start; j <= selectedRange.end; j++) {
                    Recipe r = (Recipe) tableView.getTableData().get(j);
                    selectedRecipeList.add(r);
                }
                selectedRecipe = null;
                if (selectedRecipeList.getLength() == 1) {
                    selectedRecipe = selectedRecipeList.get(0);
                }
            }
        }
    };
    TabPaneListener tabListener = new TabPaneListener.Adapter() {

        @Override
        public void tabInserted(TabPane tp, int i) {
            tp.setSelectedIndex(i);
            if (i > 0) {
                tp.setCloseable(true);
            }
        }

        @Override
        public void tabsRemoved(TabPane tp, int i, Sequence<Component> sqnc) {
            if (i > 0) {
                tp.setSelectedIndex(i - 1);
            }
            // The last tab cannot be closed
            if (i == 1) {
                tp.setCloseable(false);
            }
            if (sqnc.get(0) instanceof RecipeEditorPane) {
                recipeEditorPane = null;
            }
        }
    };
    TabPaneSelectionListener tabSelectionListener = new TabPaneSelectionListener.Adapter() {

        @Override
        public void selectedIndexChanged(TabPane tp, int previousSelectedIndex) {
            int i = tp.getSelectedIndex();
            if (i == 0) {
                tp.setCloseable(false);
                selectedRecipe = null;
            } else {
                selectedRecipeList.clear();
                //System.out.println("update current recipe tab " + i);
                if (tp.getTabs().get(i) instanceof RecipeTab) {
                    recipeTab = (RecipeTab) tp.getTabs().get(i);
                    // here we must update the selected recipe according to the selected tab
                    Recipe r = recipeTab.getRecipe();
                    selectedRecipeList.add(r);
                    selectedRecipe = r;
                }
                tp.setCloseable(true);
            }
        }
    };
    private Window.ActionMapping keyboardActionCTRLW = new Window.ActionMapping(new Keyboard.KeyStroke(Keyboard.KeyCode.W, Keyboard.Modifier.CTRL.getMask()), new Action() {

        @Override
        public void perform(Component cmpnt) {
            int i = recipeTabPane.getSelectedIndex();
            if (i > 0) {
                recipeTabPane.getTabs().remove(i, 1);
                if (i < recipeTabPane.getTabs().getLength()) {
                    recipeTabPane.setSelectedIndex(i);
                }
            }
        }
    });

    private Window.ActionMapping keyboardActionCTRLN = new Window.ActionMapping(new Keyboard.KeyStroke(Keyboard.KeyCode.N, Keyboard.Modifier.CTRL.getMask()), new Action() {
        @Override
        public void perform(Component cmpnt) {
            //groupTextInput.setText("New Collection");
            newGroupDialog.open(window);
        }
    });

    private ComponentKeyListener tableKeyListener = new ComponentKeyListener.Adapter() {

        @Override
        public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
            if (recipeTablePane.isShowing()) {
                if (keyCode == Keyboard.KeyCode.DELETE) {
                    if (!isSelectedRecipeListEmpty()) {
                        String s = "";
                        for (Recipe r : selectedRecipeList) {
                            s += r.getName() + " ";
                        }
                        String title = "Permanently delete recipe(s) \"" + s + "\"?";
                        new Alert(MessageType.QUESTION, title, new ArrayAdapter("Delete", "Cancel")).open(window, new DialogCloseListener() {
                            public void dialogClosed(Dialog dialog, boolean modal) {
                                if (((Alert) dialog).getSelectedOption().equals("Delete")) {
                                    deleteRecipes();
                                } else {
                                    dialog.close();
                                }
                                ;
                            }
                        });
                    }
                }
            }
            return false;
        }
    };

    private ComponentMouseButtonListener combl = new ComponentMouseButtonListener.Adapter() {

        @Override
        public boolean mouseClick(Component c, Mouse.Button b, int x, int y, int count) {
            // liste a double-click
            if (count == 2) {
                openRecipeTab();
            }
            return (count == 2);// ? true : false;
        }
    };

    private ComponentKeyListener cokl = new ComponentKeyListener.Adapter() {

        @Override
        public boolean keyPressed(Component comp, int keyCode, Keyboard.KeyLocation kl) {
            if (keyCode == Keyboard.KeyCode.ENTER) {
                openRecipeTab();
                return true;
            } else {
                return false;
            }

        }
    };

    private ComponentKeyListener cokl2 = new ComponentKeyListener.Adapter() {

        @Override
        public boolean keyPressed(Component comp, int keyCode, Keyboard.KeyLocation kl) {
            if (keyCode == Keyboard.KeyCode.ENTER) {
                addGroupNode();
                groupTextInput.setText("");
                newGroupDialog.close();
                return true;
            } else {
                return false;
            }

        }
    };

    private void newRecipeEditorPane() {
        recipeEditorPane = RecipeEditorPane.newInstance();
        PushButton cancelButton = recipeEditorPane.getButton("cancelButton");
        PushButton saveButton = recipeEditorPane.getButton("saveButton");
        PushButton saveAsNewButton = recipeEditorPane.getButton("saveAsNewButton");
        cancelButton.getButtonPressListeners().add(cancelButtonListener);
        saveButton.getButtonPressListeners().add(saveButtonListener);
        saveAsNewButton.getButtonPressListeners().add(saveAsNewButtonListener);
    }

    private final ButtonPressListener cancelButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {
            // if we are editing a recipe then the cancel button returns the
            int index = recipeTabPane.getSelectedIndex();
            recipeTabPane.getTabs().remove(recipeTabPane.getSelectedTab());
            if (previousTab != null) {
                recipeTabPane.getTabs().insert(previousTab, index);
            }
        }
    };
    private final ButtonPressListener saveButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {
            try {
                recipeEditorPane.saveRecipe(false);
                // we must filter the recipeList or the list will have a null element.
                recipeTablePane.updateFilter();
                int index = recipeTabPane.getSelectedIndex();
                if (previousTab != null) {
                    //previousTab.setRecipeData(selectedRecipe);
                    selectedRecipe = recipeEditorPane.getEditedRecipe();
                    //previousTab.setRecipeData(recipeEditorPane.getEditedRecipe());
                    previousTab.setRecipe(selectedRecipe);
                    recipeTabPane.getTabs().remove(recipeTabPane.getSelectedTab());
                    recipeTabPane.getTabs().insert(previousTab, index);
                } else {
                    recipeTabPane.getTabs().remove(recipeTabPane.getSelectedTab());
                }
            } catch (SaveRecipeException e) {
                Alert.alert(MessageType.ERROR, e.getMessage(), window);
            } catch (GetProcedureException e) {
                Alert.alert(MessageType.ERROR, e.getMessage(), window);
            }
        }
    };

    private final ButtonPressListener saveAsNewButtonListener = new ButtonPressListener() {

        @Override
        public void buttonPressed(Button button) {
            try {
                recipeEditorPane.saveRecipe(true);
                Recipe newRecipe = recipeEditorPane.getNewRecipe();
                recipeTablePane.updateFilter();
                int index = recipeTabPane.getSelectedIndex();
                recipeTabPane.getTabs().remove(recipeTabPane.getSelectedTab());
                //openRecipeTab(newRecipe);
            } catch (Exception e) {
                System.out.println("Empty name...");
                //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }

        }
    };

    private boolean isRecipeSelected() {
        if (selectedRecipe == null) {
            Alert.alert(MessageType.ERROR, "Please select a recipe. You can edit one recipe at time", window);
            return false;
        } else {
            return true;
        }
    }

    private boolean isSelectedRecipeListEmpty() {
        if (selectedRecipeList.isEmpty()) {
            Alert.alert(MessageType.ERROR, "Please select a recipe.", window);
            return true;
        } else {
            return false;
        }

    }

    private void openRecipeTab(Recipe r) {
        selectedRecipe = r;
        // Create a new tab and display the recipe
        BXMLSerializer bxmlSerializer = new BXMLSerializer();
        try {
            recipeTab = (RecipeTab) bxmlSerializer.readObject(getClass().getResource("recipe_tab.bxml"));
        } catch (IOException ex) {
            Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SerializationException ex) {
            Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
        }
        recipeTab.setRecipe(r);
        recipeTabPane.getTabs().add(recipeTab);

    }

    private void openRecipeTab() {
        // Create a new tab and display the recipe
        int index = -1;
        List<Recipe> tmpList = new ArrayList<Recipe>(selectedRecipeList);
        if (tmpList.isEmpty()) {
            if (selectedRecipe != null) tmpList.add(selectedRecipe);
        }
        //for (Recipe r : selectedRecipeList) {
        for (Recipe r : tmpList) {
            selectedRecipe = r;
            //if (selectedRecipe != null) {
            // Check if some of the opened tabs is associated to the selected recipe. In that
            // case just select the corresponding tab.

            // Note: the first tab cannot be cast to a RecipeTab! this is why we need a
            // castexception catch.
            for (Component co : recipeTabPane.getTabs()) {
                try {
                    RecipeTab rt = (RecipeTab) co;
                    if (rt.getRecipe().equals(selectedRecipe)) {
                        index = recipeTabPane.getTabs().indexOf(co);
                        if (index > 0) break;
                    }
                } catch (ClassCastException cce) {
                    // the first tab cannot be cast to RecipeTab it is a simple tablepane
                    //System.out.println("cannot cast");
                }
            }
            if (index == -1) {
                try {
                    // remember that each serializer has its own namespace. One serializer cannot load two tabs
                    // or we have name clashes.
                    BXMLSerializer bxmlSerializer = new BXMLSerializer();
                    recipeTab = (RecipeTab) bxmlSerializer.readObject(getClass().getResource("recipe_tab.bxml"));
                } catch (IOException ex) {
                    Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SerializationException ex) {
                    Logger.getLogger(BakeNoteWindow.class.getName()).log(Level.SEVERE, null, ex);
                }
                if (selectedRecipe != null) {
                    //System.out.println("listener selected index " + selectedRecipeIndex);
                    recipeTab.setRecipe(selectedRecipe);
                } else {
                    System.out.println("null recipe");
                }
                recipeTabPane.getTabs().add(recipeTab);
            }
        }
        if (index > 0) recipeTabPane.setSelectedIndex(index);
    }


    DropTarget groupTreeDropTarget = new DropTarget() {

        @Override
        public DropAction dragEnter(Component component, Manifest dragContent, int supportedDropActions, DropAction userDropAction) {
            DropAction dropAction = null;

            if (DropAction.MOVE.isSelected(supportedDropActions)) {
                try {
                    if (dragContent.containsText()) {
                        if (dragContent.getText().equals("recipe")) {
                            dropAction = DropAction.MOVE;
                        }
                    }
                } catch (IOException e) {
                    dropAction = null;
                    //e.printStackTrace();
                }
            }
            return dropAction;
        }

        @Override
        public void dragExit(Component component) {
            //No-op
        }

        @Override
        public DropAction dragMove(Component component, Manifest dragContent, int supportedDropActions, int x, int y, DropAction userDropAction) {

            DropAction dropAction = null;
            TreeView treeView = (TreeView) component;
            //System.out.println("move coord "+x+" " +y);
            try {
                if (dragContent.containsText()) {
                    if (dragContent.getText().equals("recipe")) {
                        //treeView.getNodeRenderer().getStyles().put("font",new Font("Verdana", Font.BOLD, 14));
                        dropAction = DropAction.MOVE;
                    }
                }
            } catch (IOException e) {
                dropAction = null;
                //e.printStackTrace();
            }
            return dropAction;
        }

        @Override
        public DropAction userDropActionChange(Component component, Manifest dragContent, int supportedDropActions, int x, int y, DropAction userDropAction) {
            DropAction dropAction = null;

            if (DropAction.MOVE.isSelected(supportedDropActions)) {
                try {
                    if (dragContent.containsText()) {
                        if (dragContent.getText().equals("recipe")) {
                            dropAction = DropAction.MOVE;
                        }
                    }
                } catch (IOException e) {
                    dropAction = null;
                    //e.printStackTrace();
                }
            }
            return dropAction;
        }

        @Override
        public DropAction drop(Component component, Manifest dragContent, int supportedDropAction, int x, int y, DropAction userDropAction) {
            DropAction dropAction = null;
            String text = null;

            TreeView treeView = (TreeView) component;
            try {
                text = dragContent.getText();
                if (text != null) {
                    if (text.equals("recipe")) {
                        // y is referred to the main container so we have to map it to the treeView
                        int my = treeView.mapPointFromAncestor(recipeTabPane, x, y).y;
                        dropAction = DropAction.MOVE;
                        int rowIndex = treeView.getRowIndex(treeView.getNodeAt(my));
                        if (rowIndex > 0) {
                            RecipeGroup recipeGroup = RecipeGroupList.getGroup(rowIndex - 1);
                            //Recipe recipe = (Recipe) dragContent.getValue("recipe");
                            List<Recipe> dropRecipeList = (List<Recipe>) dragContent.getValue("recipe");
                            for (Recipe recipe : dropRecipeList) {
                                if (!recipeGroup.contains(recipe.getUUID())) {
                                    recipeGroup.add(recipe);
                                    try {
                                        RecipeSQLiteDB.updateGroupMembers(recipeGroup);
                                    } catch (SQLException e) {
                                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (IOException e) {
                dropAction = null;
            }
            dropAction = DropAction.MOVE;

            dragExit(component);

            return dropAction;
        }
    };


    private MenuHandler treeMenuHandler = new MenuHandler.Adapter() {

        @Override
        public boolean configureContextMenu(Component cmpnt, Menu menu, int x, int y) {

            TreeView tv = (TreeView) cmpnt;
            final Tree.Path groupNodePath = tv.getNodeAt(y);
            final int treeIndex = tv.getRowIndex(groupNodePath);

            // Create the context menu
            Menu.Section menuSection1 = new Menu.Section();
            Menu.Section menuSection2 = new Menu.Section();
            Menu.Item newCollectionMenuItem = new Menu.Item("New collection");
            Menu.Item renameCollectionMenuItem = new Menu.Item("Rename collection");
            Menu.Item removeCollectionMenuItem = new Menu.Item("Remove collection");

            menu.getSections().add(menuSection1);
            menu.getSections().add(menuSection2);

            menuSection1.add(newCollectionMenuItem);
            menuSection2.add(renameCollectionMenuItem);
            menuSection2.add(removeCollectionMenuItem);

            if (treeIndex == 0) {
                renameCollectionMenuItem.setEnabled(false);
                removeCollectionMenuItem.setEnabled(false);
                newCollectionMenuItem.setAction(new Action() {
                    @Override
                    public void perform(Component source) {
                        newGroupDialog.open(window);
                    }
                });
            } else {
                renameCollectionMenuItem.setEnabled(true);
                removeCollectionMenuItem.setEnabled(true);

                removeCollectionMenuItem.setAction(new Action() {
                    @Override
                    public void perform(Component source) {
                        RecipeGroup recipeGroup = (RecipeGroup) RecipeGroupList.getNode(treeIndex - 1).getUserData();
                        String title = "Permanently delete group \""+recipeGroup.getName()+"\"?";
                        new Alert(MessageType.QUESTION, title, new ArrayAdapter("Delete", "Cancel")).open(window, new DialogCloseListener() {
                        public void dialogClosed(Dialog dialog, boolean modal) {
                            if (((Alert) dialog).getSelectedOption().equals("Delete")) {
                                deleteGroup();
                            } else {
                                dialog.close();
                            }
                        ;
                    }
                });
                    }
                });

                renameCollectionMenuItem.setAction(new Action() {
                    @Override
                    public void perform(Component component) {
                        //Not yet implemented
                        groupTreeView.setNodeEditor(new TreeViewGroupNodeEditor(treeIndex));
                        groupTreeView.getNodeEditor().beginEdit(groupTreeView, groupNodePath);
                    }
                });
            }
            return false;
        }
    };


    public void initialize(Map<String, Object> map, URL url, Resources rsrcs) {

        // cache the pointer to the main window
        window = this;

        // Set window icon
        String imageName = "bakenote/ui/icons/bake-icon.png";
        ClassLoader loader = BakeNoteWindow.class.getClassLoader();
        this.setIcon(loader.getResource(imageName));

        this.getComponentKeyListeners().add(tableKeyListener);
        this.getActionMappings().add(keyboardActionCTRLW);
        this.getActionMappings().add(keyboardActionCTRLN);

        recipeTablePane.getRecipeTableView().getComponentMouseButtonListeners().add(combl);
        recipeTablePane.getRecipeTableView().getComponentKeyListeners().add(cokl);
        recipeTablePane.getRecipeTableView().getTableViewSelectionListeners().add(recipeTableViewSelectionListener);

        groupTreeView.setMenuHandler(treeMenuHandler);
        groupTreeView.getStyles().put("font", new Font("Verdana", Font.PLAIN, 14));
        groupTreeView.setTreeData(RecipeGroupList.getGroupList());
        groupTreeView.getTreeViewSelectionListeners().add(new TreeViewSelectionListener.Adapter() {
            @Override
            public void selectedNodeChanged(TreeView treeView, Object o) {
                int index = treeView.getRowIndex(treeView.getSelectedPath());
                if (index > 0) {
                    RecipeGroup rg = ((RecipeGroup) ((TreeNode) treeView.getSelectedNode()).getUserData());
                    selectedRecipeGroup = rg;
                    recipeTablePane.setGroup(rg);
                } else {
                    recipeTablePane.setGroup(null);
                }
            }
        });
        ((TreeBranch) groupTreeView.getTreeData()).setComparator(new TreeNodeComparator());
        groupTreeView.expandAll();

        recipeTabPane.getTabPaneListeners().add(tabListener);

        recipeTabPane.getTabPaneSelectionListeners().add(tabSelectionListener);

        recipeTabPane.setTabDataRenderer(new TabButtonDataRenderer(75));

        addRecipeMenuItem.getButtonPressListeners().add(addRecipeMenuItemListener);

        editRecipeMenuItem.getButtonPressListeners().add(editRecipeMenuItemListener);

        deleteRecipeMenuItem.getButtonPressListeners().add(deleteButtonListener);

        exportMenuItem.getButtonPressListeners().add(exportButtonListener);
        importMenuItem.getButtonPressListeners().add(importButtonListener);
        databaseMenuItem.getButtonPressListeners().add(databaseButtonListener);

        aboutMenuItem.getButtonPressListeners().add(new ButtonPressListener() {
            public void buttonPressed(Button button) {
                aboutDialog.open(window);
            }
        });

        groupTreeView.setDropTarget(groupTreeDropTarget);

        // Create the dialog to add a new group
        try {
            BXMLSerializer bxmlSerializer = new BXMLSerializer();
            newGroupDialog = (Dialog) bxmlSerializer.readObject(this.getClass(), "new_group_dialog.bxml");
            newGroupDialog.getComponentKeyListeners().add(cokl2);
            groupTextInput = ((TextInput) bxmlSerializer.getNamespace().get("groupNameInput"));
            // Add the listner to the newGroupDialog
            groupOKButton = ((PushButton) bxmlSerializer.getNamespace().get("groupOKButton"));
            groupOKButton.getButtonPressListeners().add(new ButtonPressListener() {
                @Override
                public void buttonPressed(Button button) {
                    //To change body of implemented methods use File | Settings | File Templates.
                    addGroupNode();
                    groupTextInput.setText("");
                    newGroupDialog.close();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SerializationException e) {
            e.printStackTrace();
        }
    }

    private void addGroupNode() {
        try {
            RecipeGroup rg = new RecipeGroup(groupTextInput.getText());
            rg.createUUID();
            RecipeGroupList.add(rg);
            RecipeSQLiteDB.saveGroup(rg);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void deleteGroup() {
        if (selectedRecipeGroup != null) {
            RecipeGroupList.remove(selectedRecipeGroup);
            RecipeSQLiteDB.deleteGroup(selectedRecipeGroup);
        }
    }

    private void deleteRecipes() {
        if (!selectedRecipeList.isEmpty()) {
            List<Recipe> removedRecipes = new ArrayList<Recipe>();
            for (Recipe r : selectedRecipeList) {
                removedRecipes.add(r);
            }
            for (Recipe r : removedRecipes) {
                RecipeSQLiteDB.deleteRecipe(r);
                RecipeList.remove(r);
                for (int j = 0; j < recipeTabPane.getTabs().getLength(); j++) {
                    Component co = recipeTabPane.getTabs().get(j);
                    try {
                        RecipeTab rt = (RecipeTab) co;
                        if (rt.getRecipe().equals(r)) {
                            int index = recipeTabPane.getTabs().indexOf(co);
                            recipeTabPane.getTabs().remove(index, 1);
                        }
                    } catch (ClassCastException cce) {
                        //No-op
                    }
                }
            }
        }
    }

    private class TreeViewGroupNodeEditor extends TreeViewNodeEditor {

        private final RecipeGroup recipeGroup;

        public TreeViewGroupNodeEditor(int index) {
            this.getTextInput().getStyles().put("font", new Font("Verdana", Font.PLAIN, 14));
            recipeGroup = (RecipeGroup) RecipeGroupList.getNode(index - 1).getUserData();
            System.out.println("updating recipe group name " + recipeGroup.getName());
        }

        @Override
        public void endEdit(boolean result) {
            // remove the editor from the treView
            try {
                recipeGroup.setName(this.getTextInput().getText());
                System.out.println("new recipe group name " + recipeGroup.getName());
                RecipeSQLiteDB.updateGroupName(recipeGroup, getTextInput().getText());
                System.out.println("updated recipe group name " + recipeGroup.getName());
            } catch (SQLException e) {
                System.out.println("Cannot update recipe group name");
            }
            super.endEdit(result);
            groupTreeView.setNodeEditor(null);
        }
    }
}
